/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.mes.base.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import org.springblade.modules.mes.base.utils.StringUtils;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springblade.modules.mes.base.entity.MaterialInfo;
import org.springblade.modules.mes.base.entity.PrdBom;
import org.springblade.modules.mes.base.entity.PrdBomParam;
import org.springblade.modules.mes.base.entity.PrdBomStation;
import org.springblade.modules.mes.base.mapper.PrdBomMapper;
import org.springblade.modules.mes.base.service.IPrdBomParamService;
import org.springblade.modules.mes.base.service.IPrdBomService;
import org.springblade.modules.mes.base.service.IPrdBomStationService;
import org.springblade.modules.mes.base.vo.PrdBomVO;
import org.springblade.modules.mes.base.vo.ScanItemVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 产品BOM信息 服务实现类
 *
 * @author BladeX
 * @since 2021-03-11
 */
@Service
@AllArgsConstructor
public class PrdBomServiceImpl extends BaseServiceImpl<PrdBomMapper, PrdBom> implements IPrdBomService {
	private final IPrdBomStationService prdBomStationService;
	private final IPrdBomParamService prdBomParamService;

	@Override
	public IPage<PrdBomVO> selectPrdBomPage(IPage<PrdBomVO> page, PrdBomVO prdBom) {
		return page.setRecords(baseMapper.selectPrdBomPage(page, prdBom));
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean saveBom(PrdBomVO prdBomVO) {
		prdBomVO.setAuditStatus("1");//保存时
		PrdBom prdBom = baseMapper.selectOne(new QueryWrapper<PrdBom>().eq("material_no",prdBomVO.getMaterialNo())
				.last(" and (direct_leader_no is null or direct_leader_no='')"));
		if (prdBom==null) {
			super.save(prdBomVO);//保存上边的bom作为顶级
		}
		if (ObjectUtil.isNotEmpty(prdBomVO.getConnectNo())){
			PrdBom prdBomConnect = baseMapper.selectOne(new QueryWrapper<PrdBom>().lambda().eq(PrdBom::getMaterialNo,prdBomVO.getConnectNo()).eq(PrdBom::getIsDeleted, 0).last("limit 1"));
			if (ObjectUtil.isNotEmpty(prdBomConnect)){
				prdBomConnect.setConnectNo(prdBomVO.getMaterialNo());
				super.saveOrUpdate(prdBomConnect);
			}
		}
		List<PrdBomVO> childPrdBoms = prdBomVO.getChildPrdBomList();
		if (CollectionUtil.isNotEmpty(childPrdBoms)){
			List<PrdBom> childBoms= new ArrayList<>();
			childPrdBoms.forEach(item->{
				item.setDirectLeaderNo(prdBomVO.getMaterialNo());
				item.setId(null);
				childBoms.add(item);
			});
			super.saveBatch(childBoms);//保存下面的子bom列表
		}

		prdBomStationService.deleteByProduceNo(prdBomVO.getMaterialNo());
		if (ObjectUtil.isNotEmpty(prdBomVO.getChildPrdBomStationList())){
			prdBomVO.getChildPrdBomStationList().forEach(prdBomStation -> {
				prdBomStation.setId(null);
				prdBomStationService.save(prdBomStation);
			});
		}
		prdBomParamService.deleteByProduceNo(prdBomVO.getMaterialNo());
		if (ObjectUtil.isNotEmpty(prdBomVO.getChildPrdBomParamList())){
			prdBomVO.getChildPrdBomParamList().forEach(prdBomParam -> {
				prdBomParam.setId(null);
				prdBomParamService.save(prdBomParam);
			});
		}
		return true;
	}
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean deleteBoms(List<Long> ids) {
		List<PrdBom> deleteBoms = super.list(new QueryWrapper<PrdBom>().in("id", ids));//要删除的bom
		for (PrdBom bom:deleteBoms) {
			if (StringUtils.isEmpty(bom.getDirectLeaderNo())) {//如果是顶级才删除下级否则只删除本级
				List<String> directNos = deleteBoms.stream().map(item -> item.getMaterialNo()).collect(Collectors.toList());
				List<PrdBom> subBoms = baseMapper.selectList(new QueryWrapper<PrdBom>().in("direct_leader_no", directNos));
				List<String> subNos = subBoms.stream().map(item -> item.getMaterialNo()).collect(Collectors.toList());
				if (CollectionUtil.isNotEmpty(subNos) && CollectionUtil.isNotEmpty(directNos)) {
					baseMapper.deleteBoms(directNos, subNos);//删除下级
				}
				prdBomStationService.deleteByProduceNo(bom.getMaterialNo());
				prdBomParamService.deleteByProduceNo(bom.getMaterialNo());

			}
		}
		return baseMapper.deleteByIds(ids);//删除本级
	}

	/**
	 * 获取下级编码
	 * @param bomList
	 * @param allBom
	 * @return
	 */
	private List<String> getSubBom(List<PrdBom> bomList,List<String> allBom) {
		allBom.addAll(bomList.stream().map(item -> item.getMaterialNo()).collect(Collectors.toList()));
		for (PrdBom bom:bomList){
			List<PrdBom> prdBoms = super.list(new QueryWrapper<PrdBom>().eq("direct_leader_no",bom.getMaterialNo()));
			if (CollectionUtil.isNotEmpty(prdBoms)){
				getSubBom(prdBoms,allBom);
			}
		}
		return allBom;
	}

	@Transactional(rollbackFor = Exception.class)
	public void deleteBom(List<String> materialNo,String topProductNo) {
		List<PrdBom> deleteBoms = super.list(new QueryWrapper<PrdBom>().in("material_no", materialNo).eq("top_product_no",topProductNo));//要删除的bom
		for(PrdBom deleteBom : deleteBoms){
			//要删除的bom及所有下级的编码
//			List<String> deleteBomAndSubPrdNos = super.list(new QueryWrapper<PrdBom>().eq("direct_leader_no", deleteBom.getMaterialNo()))
//					.stream().map(item -> item.getMaterialNo()).collect(Collectors.toList());
//			deleteBomAndSubPrdNos.add(deleteBom.getMaterialNo());
			List<PrdBom> bomList = super.list(new QueryWrapper<PrdBom>().eq("direct_leader_no", deleteBom.getMaterialNo()));
			List<String> deleteBomAndSubPrdNos =getSubBom(bomList,new ArrayList<>());

			deleteBomAndSubPrdNos.add(deleteBom.getMaterialNo());
			//要删除的bom，在哪些顶级产品下
//			List<String> deleteTopPrdNos = super.list(new QueryWrapper<PrdBom>().eq("material_no", deleteBom.getMaterialNo()))
//					.stream().map(item -> item.getTopProductNo()).distinct().collect(Collectors.toList());

			//把这些顶级产品下的，这个bom以及他的下级的编码全删掉，物理删除
			baseMapper.deleteBoms(Func.toStrList(topProductNo), deleteBomAndSubPrdNos);
//			super.remove(new QueryWrapper<PrdBom>().in("top_product_no", deleteTopPrdNos).in("material_no", deleteBomAndSubPrdNos));
		}
	}
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean updateBom(PrdBomVO prdBomVO) {
		List<PrdBom> oldChildBom = super.list(new QueryWrapper<PrdBom>().eq("direct_leader_no",prdBomVO.getMaterialNo()).ne("material_no",prdBomVO.getMaterialNo()));
		List<PrdBomVO> newChildBom = prdBomVO.getChildPrdBomList();
		List<String> oldChildNo = oldChildBom.stream().map(item -> item.getMaterialNo()).collect(Collectors.toList());
//		List<String> newChildNo =newChildBom.stream().map(item -> item.getMaterialNo()).collect(Collectors.toList());
//		List<String> deletedNo = new ArrayList<>();
//		for (String str:oldChildNo){
//			if (!newChildNo.contains(str)){
//				deletedNo.add(str);
//			}
//		}
		if (CollectionUtil.isNotEmpty(oldChildNo)){
			baseMapper.deleteBoms(Func.toStrList(prdBomVO.getMaterialNo()),oldChildNo);
		}
		if (CollectionUtil.isNotEmpty(newChildBom)){
			List<PrdBom> childBoms= new ArrayList<>();
			newChildBom.forEach(item->{
				item.setDirectLeaderNo(prdBomVO.getMaterialNo());
				item.setId(null);
				childBoms.add(item);
			});
			super.saveOrUpdateBatch(childBoms);//保存下面的子bom列表
		}
		prdBomStationService.deleteByProduceNo(prdBomVO.getMaterialNo());
		if (ObjectUtil.isNotEmpty(prdBomVO.getChildPrdBomStationList())){
			prdBomVO.getChildPrdBomStationList().forEach(prdBomStation -> {
				prdBomStation.setId(null);
				prdBomStationService.save(prdBomStation);
			});
		}
		prdBomParamService.deleteByProduceNo(prdBomVO.getMaterialNo());
		if (ObjectUtil.isNotEmpty(prdBomVO.getChildPrdBomParamList())){
			prdBomVO.getChildPrdBomParamList().forEach(prdBomParam -> {
				prdBomParam.setId(null);
				prdBomParamService.save(prdBomParam);
			});
		}
		return super.updateById(prdBomVO);
	}

	/*@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean updateBom(PrdBomVO prdBomVO) {
//		List<PrdBom> list = super.list(new QueryWrapper<PrdBom>().eq("material_no", prdBomVO.getMaterialNo()));
//		List<String> fatherNos = list.stream().map(item -> item.getDirectLeaderNo()).collect(Collectors.toList());
//		List<PrdBom> fatherBoms = super.list(new QueryWrapper<PrdBom>().in("material_no", fatherNos));



		List<PrdBom> oldChildBom = super.list(new QueryWrapper<PrdBom>().eq("direct_leader_no",prdBomVO.getMaterialNo()).ne("material_no",prdBomVO.getMaterialNo()));
		List<PrdBomVO> newChildBom = prdBomVO.getChildPrdBomList();
		List<String> oldChildNo = oldChildBom.stream().map(item -> item.getMaterialNo()).collect(Collectors.toList());
		List<String> newChildNo =newChildBom.stream().map(item -> item.getMaterialNo()).collect(Collectors.toList());
		List<String> deletedNo = new ArrayList<>();
		for (String str:oldChildNo){
			if (!newChildNo.contains(str)){
				deletedNo.add(str);
			}
		}
		if (CollectionUtil.isNotEmpty(deletedNo)){
			this.deleteBom(deletedNo,prdBomVO.getTopProductNo());
		}

//		//1.先删除bom
//		List<Long> deleteIds = new ArrayList<>();
//		deleteIds.add(prdBomVO.getId());
//		this.deleteBoms(deleteIds);

		for (int i=0; i<newChildBom.size();i++) {
			//如果是新增
			if (!oldChildNo.contains(newChildBom.get(i).getMaterialNo())) {
				//选择的下级中，存在bom的，把整个bom结构带过来
				List<PrdBom> hasBomlist = super.list(new QueryWrapper<PrdBom>().eq("top_product_no", newChildBom.get(i).getMaterialNo()));
				//选择的下级中，不存在bom的，直接设置上级编码、顶级编码
//		List<String> hasBomPrdNos = hasBomlist.stream().filter(item -> item.getMaterialNo().equals(item.getTopProductNo()))
//				.map(item -> item.getMaterialNo()).collect(Collectors.toList());

				for (PrdBom item : hasBomlist) {
					item.setId(null);//新增、id置空
					item.setTopProductNo(prdBomVO.getTopProductNo());
					if (item.getMaterialNo().equals(item.getTopProductNo())) {//如A的下级为B和C，B有自己的bom，此时将B整个BOM拿来，且B的上级和top都设为A，B的子集只把top设为A
						hasBomlist.remove(item);
//						item.setDirectLeaderNo(newChildBom.get(i).getMaterialNo());
					}
				}
				super.saveBatch(hasBomlist);//保存下面的子bom列表
				newChildBom.get(i).setId(null);
				newChildBom.get(i).setTopProductNo(prdBomVO.getTopProductNo());
				newChildBom.get(i).setDirectLeaderNo(prdBomVO.getMaterialNo());
			}
			super.saveOrUpdate(newChildBom.get(i));
		}

//		//2.再新增bom
//		this.saveBom(prdBomVO);
//
		super.updateById(prdBomVO);
		//3.将这个bom再挂到原来所有的上级下
//		List<PrdBom> boms = super.list(new QueryWrapper<PrdBom>().eq("top_product_no", prdBomVO.getMaterialNo()));
//		for(PrdBom fatherBom : fatherBoms){
//			List<PrdBom> saveList = boms;
//			saveList.forEach(item -> {
//				if(item.getTopProductNo().equals(item.getMaterialNo())){
//					item.setDirectLeaderNo(fatherBom.getMaterialNo());
//				}
//				item.setTopProductNo(fatherBom.getTopProductNo());
//				item.setId(null);//新增id置空
//			});
//			super.saveBatch(saveList);
//		}

		return true;
	}*/

	@Override
	public boolean saveOrUpdate(PrdBom entity) {
		//如果是新增
		if (entity.getId()==null) {
			//选择的下级中，存在bom的，把整个bom结构带过来
			List<PrdBom> hasBomlist = super.list(new QueryWrapper<PrdBom>().eq("top_product_no", entity.getMaterialNo()));
			//选择的下级中，不存在bom的，直接设置上级编码、顶级编码
//		List<String> hasBomPrdNos = hasBomlist.stream().filter(item -> item.getMaterialNo().equals(item.getTopProductNo()))
//				.map(item -> item.getMaterialNo()).collect(Collectors.toList());

			for (PrdBom item : hasBomlist) {
				item.setId(null);//新增、id置空
				if (item.getMaterialNo().equals(item.getTopProductNo())) {//如A的下级为B和C，B有自己的bom，此时将B整个BOM拿来，且B的上级和top都设为A，B的子集只把top设为A
					item.setDirectLeaderNo(entity.getMaterialNo());
				}
				item.setTopProductNo(entity.getMaterialNo());
			}
			super.saveBatch(hasBomlist);//保存下面的子bom列表
		}
		return super.saveOrUpdate(entity);
	}

	@Override
	public PrdBomVO getDetail(String id) {
		PrdBomVO vo = baseMapper.getDetail(id);
		List<PrdBomVO> childPrdBomList = baseMapper.selectChildPrdBomList(vo);
		vo.setChildPrdBomList(childPrdBomList);
		List<PrdBomStation> childPrdBomStationList = prdBomStationService.list(new QueryWrapper<PrdBomStation>().lambda()
			.eq(PrdBomStation::getProduceNo,vo.getMaterialNo()).eq(PrdBomStation::getIsDeleted,0));
		vo.setChildPrdBomStationList(childPrdBomStationList);
		List<PrdBomParam> childPrdBomParamList = prdBomParamService.list(new QueryWrapper<PrdBomParam>().lambda()
			.eq(PrdBomParam::getProduceNo,vo.getMaterialNo()).eq(PrdBomParam::getIsDeleted,0));
		vo.setChildPrdBomParamList(childPrdBomParamList);
		return vo;
	}

	@Override
	public List<PrdBomVO> listByTopNo(String topProductNo) {
		return baseMapper.listByTopNo(topProductNo, AuthUtil.getTenantId());
	}

	@Override
	public List<PrdBomVO> getBomList(PrdBomVO prdBomVO){
		return baseMapper.getBomList(prdBomVO);
	}

	@Override
	public List<PrdBomVO> getMaterialListByLeaderNo(PrdBomVO prdBomVO){
		return baseMapper.getMaterialListByLeaderNo(prdBomVO);
	}
	@Override
	public List<PrdBomVO> getAMList(){
		return baseMapper.getAMList(AuthUtil.getTenantId());
	}
	@Override
	public 	List<MaterialInfo> getMaterialList(List<String> list){
		return baseMapper.getMaterialList(list);
	}
	//已废弃
	@Override
	public List<Map<String, Object>> getBomByProductId(Long productId, String materialType) {
		List<Map<String,Object>> bomList = baseMapper.getBomByProductId(productId);
		List<Map<String,Object>> returnList = new ArrayList<>();
		String tenantId = AuthUtil.getTenantId();
		if (CollectionUtil.isNotEmpty(bomList)){
			for (Map map:bomList){
				if (materialType.equals(map.get("materialType"))){
//					if (map.get("boxCounts")!=null){
//						map.put("boxCounts",map.get("boxCounts"));
//					}
					returnList.add(map);
				}
				List<PrdBomVO> prdBomVOS = baseMapper.listByTopNo((String) map.get("materialNo"),tenantId);
				if (CollectionUtil.isNotEmpty(prdBomVOS)){
					getSubMaterial(returnList,materialType,prdBomVOS);
				}
			}
		}

		//产品本身加到数据里面
		List<Map<String, Object>> bom = baseMapper.getProductId(productId);
		if (CollectionUtil.isNotEmpty(bom)){
			for (Map map:bom){
				if (materialType.equals(map.get("materialType"))){
					returnList.add(map);
				}
			}
		}
		return returnList;
	}
	//已废弃
	private List<Map<String,Object>> getSubMaterial(List<Map<String, Object>> returnList, String materialType, List<PrdBomVO> prdBomVOS) {
		String tenantId = AuthUtil.getTenantId();
		if (CollectionUtil.isNotEmpty(prdBomVOS)) {
			prdBomVOS.forEach(item -> {
				if (materialType.equals(item.getProductType())) {
					Map<String, Object> resMap = new HashMap<>();
					resMap.put("id", item.getProductId());
					resMap.put("materialNo", item.getMaterialNo());
					resMap.put("materialName", item.getMaterialName());
					resMap.put("materialType", item.getProductType());
					int boxCounts=0;
					if (StringUtils.isNotEmpty(item.getBoxCounts())){
						boxCounts = (int)(Double.parseDouble(item.getBoxCounts()));
					}
					resMap.put("boxCounts", boxCounts);
					returnList.add(resMap);
				}
				List<PrdBomVO> prdBomVO = baseMapper.listByTopNo(item.getMaterialNo(),tenantId);
				if (CollectionUtil.isNotEmpty(prdBomVO)){
					getSubMaterial(returnList,materialType,prdBomVO);
				}
			});
		}
		return returnList;
	}

	@Override
	public List<PrdBomVO> selectByTopNo(String productNo,String tenantId) {
		List<PrdBomVO> prdBomVOS = baseMapper.listByTopNo(productNo,tenantId);
//		prdBomVOS.forEach(item->{
//			List<String> list = new ArrayList<>();
//			list.add(item.getProductFlag());
//			list.add(item.getProductType());
//			item.setMaterialTypes(list);
//			item.setChildren(this.getBomTree(item.getMaterialNo(),tenantId));
//		});
//		List<PrdBomVO> parent = baseMapper.listParent(productNo,tenantId);
//		if (CollectionUtil.isNotEmpty(parent)) {
//			parent.get(0).setChildren(prdBomVOS);
//		}
		return prdBomVOS;
	}
	@Override
	public List<PrdBomVO> selectByTopNoVw(String productNo) {
		String tenantId = AuthUtil.getTenantId();
		List<PrdBomVO> prdBomVOS = baseMapper.listByTopNo(productNo,tenantId);
		prdBomVOS.forEach(item->{
			List<String> list = new ArrayList<>();
			list.add(item.getProductFlag());
			list.add(item.getProductType());
			item.setMaterialTypes(list);
			item.setChildren(this.getBomTree(item.getMaterialNo(),tenantId));
		});

		return prdBomVOS;
	}

    @Override
    public List<String> getParent(String materialNo) {
        return baseMapper.getParent(materialNo);
    }

    @Override
    public Map<String, Object> getBomStatus(String productNo) {
		Map<String,Object> map = new HashMap<>();
		int status = baseMapper.getBomStatus(productNo);
		map.put("bomStatus",status);
        return map;
    }


    @Override
    public List<PrdBomVO> getQuota(String productNo) {
        return baseMapper.selectQuota(productNo, AuthUtil.getTenantId());
    }
	@Override
	public List<PrdBomVO> getUnConnectList() {
		return baseMapper.getUnConnectList();
	}

	@Override
	public List<ScanItemVO> getScanList(String scanBarCode, String assemblyNo, String stationCode) {
		return baseMapper.findScanList(scanBarCode,assemblyNo,stationCode);
	}
	@Override
	public List<ScanItemVO> getScanAllList(String scanBarCode, String assemblyNo, String stationCode) {
		return baseMapper.findScanAllList(scanBarCode,assemblyNo,stationCode);
	}
	private List<PrdBomVO> getBomTree(String materialNo,String tenantId) {
		List<PrdBomVO> prdBomVOS = baseMapper.listByTopNo(materialNo,tenantId);
		if (CollectionUtil.isNotEmpty(prdBomVOS)){
			prdBomVOS.forEach(item->{
				List<String> list = new ArrayList<>();
				list.add(item.getProductFlag());
				list.add(item.getProductType());
				item.setMaterialTypes(list);
				item.setChildren(this.getBomTree(item.getMaterialNo(),tenantId));
			});
		}
		return prdBomVOS;
	}
}
